#include <algorithm> // for std::sort, std::copy
#include <iterator>  // for std::istream_iterator
#include <numeric>   // for std::accumulate
#include <stdexcept> // for std::domain_error

#include "grades.hpp"

using std::begin;
using std::end;

double median(grade_vector v)  // pass by value, copy, we can change v locally
{
    size_t size = end(v) - begin(v);
    if(size == 0) throw std::domain_error("median of an empty vector");
    std::sort(begin(v), end(v));
    size_t mid = size / 2; // integer division as this is "int / int"
    return size % 2 == 0 ? (v[mid] + v[mid-1]) / 2.0 : v[mid];
}

double average(const grade_vector& v) // pass by const reference, no copy, can't change
{
    size_t size = end(v) - begin(v);
    return std::accumulate(begin(v), end(v), double(0)) / size;
    // Note the "double(0)" as the initialization value
    // its type will be used to accumulate the result
    // I.e. writing just "0" will accumulate as integers...
}

std::istream& read_grade_vector(std::istream& in, grade_vector& v) 
    // pass by reference, no copy, if we change, caller will see
{
    std::copy(std::istream_iterator<double>(in),  // read from in
              std::istream_iterator<double>(),    // until no more double's found
              std::back_inserter(v));             // add them to end of v
    return in;
}
